using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using AUSRIS.Reports.Utilities.Deployment.Entities;
using AUSRIS.Reports.Utilities.Deployment.Logging;

namespace AUSRIS.Reports.Utilities.Deployment.FileSystem.SVNAdapter
{
    /// <summary>
    /// Subversion based IRepository implementation
    /// </summary>
    public class Repository : AbstractRepository
    {
        #region Private Fields

        private SVNInfo svnInfo;

        #endregion

        #region Dependencies

        /// <summary>
        /// Gets or sets the SVN settings
        /// </summary>
        public SVNInfo SVNInfo
        {
            get
            {
                return svnInfo;
            }
            set
            {
                svnInfo = value;
            }
        }

        #endregion

        #region IRepository Members

        public override void Checkout(CatalogFile file, string versionTag)
        {
            string url = string.Format("{0}/{1}/{2}", this.SVNInfo.RepositoryUrl, versionTag, file.SourcePath);
            string target = Path.Combine(this.GetWorkingDirectory(), versionTag);

            this.LogMessage("Checking out {0} to {1}", url, target);

            string command = string.Format("checkout --username {0} --password {1} {2} {3}", this.SVNInfo.Username, this.SVNInfo.Password, url, target);

            this.ExecuteSVN(command);
        }

        public override void CheckoutModule(string moduleName, string versionTag)
        {
            //Note: we can ignore the module name, since the repository url has all the path needed, execept for the actual branch

            string url = string.Format("{0}/{1}", this.SVNInfo.RepositoryUrl, versionTag);
            string target = Path.Combine(this.GetWorkingDirectory(), versionTag);

            this.LogMessage("Checking out {0} to {1}", moduleName, target);

            string command = string.Format("checkout --username {0} --password {1} {2} {3}", this.SVNInfo.Username, this.SVNInfo.Password, url, target);

            this.ExecuteSVN(command);
        }

        /// <summary>
        /// Set the "revision" property of the CatalogFile, with
        /// the data from entries svn file.
        /// </summary>
        /// <param name="file"></param>
        public override void SetRevision(CatalogFile file)
        {
            file.SourcePath = this.GetLocalPath(file);
            if (!File.Exists(file.SourcePath))
            {
                throw new Exception(string.Format("ERROR: '{0}' does not exist", file.Name));
            }
            string parentDirectory = Path.GetDirectoryName(file.SourcePath);
            string entriesPath = Path.Combine(parentDirectory, Path.Combine(this.SVNInfo.SvnDirectoryName, "entries"));

            string entriesText = File.ReadAllText(entriesPath);
            string[] entries = entriesText.Split(this.SVNInfo.EntriesDelimiter);

            string fileName = Path.GetFileName(file.SourcePath);

            foreach (string entry in entries) 
            {
                string trimmedEntry = entry.Trim();
                if (trimmedEntry.StartsWith(fileName)) 
                {
                    file.Revision = this.GetRevision(trimmedEntry);
                    return;
                }
            }
            //if no entry is found, the file's revision will stay blank and always get published.
        }

        #endregion

        #region Overridden Protected Methods

        protected override string GetWorkingDirectory()
        {
            return this.SVNInfo.WorkingFolder;
        }

        #endregion

        #region Private Methods

        private string GetRevision(string entry) 
        {
            string[] segments = entry.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string segment in segments) 
            {
                if (segment.Length == 32) 
                {
                    return segment;
                }
            }
            return string.Empty;
        }

        private void ExecuteSVN(string arguments)
        {
            Process proc = new Process();
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.WorkingDirectory = this.GetWorkingDirectory();
            proc.StartInfo.FileName = "svn.exe";
            proc.StartInfo.Arguments = arguments;
            proc.Start();
            proc.WaitForExit();
        }

        #endregion
    }
}
